package avicit.bdp.lineage.druid.process.tablesource;

import avicit.bdp.lineage.druid.anotation.SQLObjectType;
import avicit.bdp.lineage.druid.contants.ParserConstant;
import avicit.bdp.lineage.druid.model.ColumnNode;
import avicit.bdp.lineage.druid.model.TableNode;
import avicit.bdp.lineage.druid.model.TreeNode;
import avicit.bdp.lineage.druid.process.ProcessorRegister;
import avicit.bdp.lineage.druid.process.SqlExprContent;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLWithSubqueryClause;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * SQLExprTableSource
 * </p>
 */
@SQLObjectType(clazz = SQLExprTableSource.class)
public class SQLExprTableSourceProcessor implements TableSourceProcessor {

    @Override
    public void process(String dbType, AtomicInteger sequence, TreeNode<TableNode> parent, SQLTableSource sqlTableSource
    ) {
        // 建立TEMP节点 start
        TableNode proxyTable = TableNode.builder()
                .expression(SQLUtils.toSQLString(sqlTableSource))
                .alias(sqlTableSource.getAlias())
                .build();
        TreeNode<TableNode> proxyNode = TreeNode.of(proxyTable);
        parent.addChild(proxyNode);

        SQLExpr sqlExprTableSourceExpr = ((SQLExprTableSource) sqlTableSource).getExpr();
        SqlExprContent sqlExprContent = new SqlExprContent();
        if (sqlExprTableSourceExpr instanceof SQLQueryExpr) {
            proxyTable.setVirtualTemp(true);
            // 处理子查询,包括部分数据库支持with语法
            SQLSelect sqlSelect = ((SQLQueryExpr) sqlExprTableSourceExpr).getSubQuery();
            if (sqlSelect != null && sqlSelect.getQuery() != null) {
                ProcessorRegister.getSQLSelectQueryProcessor(sqlSelect.getQuery().getClass())
                        .process(dbType, sequence, proxyNode, sqlSelect.getQuery());
                //默认下一个子节点的列
                List<TreeNode<TableNode>> childList = proxyNode.getChildList();
                if(childList != null && childList.size()>0){
                    List<ColumnNode> columnNodeList = childList.get(0).getValue().getColumns();
                    if(columnNodeList != null){
                        proxyTable.getColumns().addAll(columnNodeList);
                    }
                }

            }
            // 构建with字段
            SQLWithSubqueryClause subqueryClause = sqlSelect.getWithSubQuery();
            if (subqueryClause != null) {
                processWithSQL(dbType, sequence, proxyNode.getRoot(), subqueryClause);
            }
        } else {
            ProcessorRegister.getSQLExprProcessor(sqlExprTableSourceExpr.getClass())
                    .process(dbType, sqlExprTableSourceExpr, sqlExprContent);
        }

        proxyTable.setName(sqlExprContent.getName());
        proxyTable.setSchemaName(sqlExprContent.getOwner());
    }

    private void processSubQuery(String dbType, AtomicInteger sequence, TreeNode<TableNode> parent,SQLSelect sqlSelect ){

    }

    public void processWithSQL(String dbType, AtomicInteger sequence, TreeNode<TableNode> parent,
                               SQLWithSubqueryClause sqlWithSubqueryClause) {
        List<SQLWithSubqueryClause.Entry> list = sqlWithSubqueryClause.getEntries();
        for (SQLWithSubqueryClause.Entry entry : list) {
            // 执行SQLSelectQuery 查询
            SQLSelectQuery sqlSelectQuery = entry.getSubQuery().getQuery();

            // 建立中间表节点
            TableNode proxyTable = TableNode.builder()
                    .isVirtualTemp(true)
                    .expression(SQLUtils.toSQLString(sqlWithSubqueryClause))
                    .name(ParserConstant.TEMP_TABLE_PREFIX + sequence.incrementAndGet())
                    .alias(entry.getAlias())
                    .build();
            TreeNode<TableNode> proxyNode = TreeNode.of(proxyTable);
            parent.addChild(proxyNode);

            ProcessorRegister.getSQLSelectQueryProcessor(sqlSelectQuery.getClass())
                    .process(dbType, sequence, proxyNode, sqlSelectQuery);
        }
    }
}
